package game.games.paint;

import game.AbstractGame;
import game.GraphicUtil;
import game.Position;
import game.console.GameConsole;
import game.console.IConsoleCommand;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.SwingUtilities;

public class Paint extends AbstractGame
{
    private static Paint instance;
    
    public synchronized static Paint getInstance()
    {
        if (instance == null)
        {
            synchronized (Paint.class)
            {
                instance = new Paint();
                for (IConsoleCommand commandObj : instance.getCommands())
                {
                    GameConsole.getInstance().addConsoleCommand(commandObj);
                }
            }
        }
        return instance;
    }
    
    public Paint()
    {
        super(true);
    }

    // map
    private CellMap       map            = new CellMap(true);
    private List<Color>   pixel          = new ArrayList<Color>();
    // mouse
    private int           mouseOverIndex = -1;
    // colors
    private final Color[] colors         = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW };
    private final Color   DEFAULT_COLOR  = Color.WHITE;
    private Color         selectedColor  = DEFAULT_COLOR;
    // reset
    private boolean       resetScreen    = true;
    
    private void resetScreen()
    {
        resetScreen = true;
    }
    
    @Override
    public void render(Graphics g)
    {
        if (resetScreen)
        {
            GraphicUtil.fillRect(g, 0, 0, getFrameSize().width, getFrameSize().height, Color.WHITE);
            resetScreen = false;
        }
        for (int index = 0; index < map.getSize().getSum(); index++)
        {
            Position position = map.calculatePosition(index);
            if (index == mouseOverIndex)
            {
                map.fillRect(g, position.getX(), position.getY(), selectedColor);
            }
            else
            {
                // paint pixel
                if (pixel.size() > index)
                {
                    Color color = pixel.get(index);
                    if (color != null)
                    {
                        map.fillRect(g, position.getX(), position.getY(), color);
                    }
                }
            }
            if (map.getCellSize() > 2)
            {
                // paint map
                map.drawRect(g, position.getX(), position.getY(), Color.BLACK);
            }
        }
    }

    @Override
    protected void doNext()
    {
        if (pixel.size() != map.getSize().getSum())
        {
            while (pixel.size() < map.getSize().getSum())
            {
                pixel.add(DEFAULT_COLOR);
            }
            while (pixel.size() > map.getSize().getSum())
            {
                pixel.remove(pixel.size() - 1);
            }
        }
    }
    
    @Override
    protected synchronized void reset()
    {
        map.setSize(map.calcMaxSize(new Position(getFrameSize())));
        super.reset();
    }
    
    @Override
    public MouseListener getMouseControl()
    {
        return new MouseAdapter() 
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if (isRunning())
                {
                    if (SwingUtilities.isRightMouseButton(e))
                    {
                        boolean currentColorFound = false;
                        int i = 0;
                        for (; i < colors.length; i++)
                        {
                            Color color = colors[i];
                            if (currentColorFound)
                            {
                                selectedColor = color;
                                return;
                            }
                            if (color == selectedColor)
                            {
                                currentColorFound = true;
                            }
                        }
                        if (i == colors.length)
                        {
                            selectedColor = colors[0];
                        }
                    }
                    else if (SwingUtilities.isLeftMouseButton(e))
                    {
                        int index = map.calculateIndex(map.calcCoord(e.getPoint()));
                        pixel.set(index, selectedColor);
                    }
                }
            }
        };
    }
    
    @Override
    public MouseMotionListener getMouseMotionListener()
    { 
        return new MouseMotionAdapter() 
        {
            @Override
            public void mouseMoved(MouseEvent e)
            {
                if (isRunning())
                {
                    mouseOverIndex = map.calculateIndex(map.calcCoord(e.getPoint())); 
                }
            }
            
            @Override
            public void mouseDragged(MouseEvent e)
            {
                if (isRunning())
                {
                    int index = map.calculateIndex(map.calcCoord(e.getPoint()));
                    if (SwingUtilities.isLeftMouseButton(e))
                    {
                        pixel.set(index, selectedColor);
                    }
                    else
                    {
                        mouseOverIndex = index;
                    }
                }
            }
        };
    }
    
    private List<IConsoleCommand> getCommands()
    {
        List<IConsoleCommand> commands = new ArrayList<IConsoleCommand>();
        commands.add(new IConsoleCommand() 
        {
            @Override
            public String getCommand()
            {
                return "colors";
            }
            
            @Override
            public String[] getSynonym()
            {
                return null;
            }
            
            @Override
            public String getInfo()
            {
                return null;
            }
            
            @Override
            public String[] fireCommand(String command)
            {
                List<String> out = new ArrayList<String>();
                out.add(colors.length + " Colors available");
                int i = 0;
                for (Color color : colors)
                {
                    out.add(i++ + " " + color);
                }
                return out.toArray(new String[out.size()]);
            }
        });
        commands.add(new IConsoleCommand() 
        {
            @Override
            public String getCommand()
            {
                return "color";
            }
            
            @Override
            public String[] getSynonym()
            {
                return null;
            }
            
            @Override
            public String getInfo()
            {
                return null;
            }
            
            @Override
            public String[] fireCommand(String command)
            {
                String message = "";
                int index = Integer.parseInt(command);
                if (index >= 0 && index < colors.length)
                {
                    selectedColor = colors[index];
                    message = "new color " + index + " = " + selectedColor;
                }
                else
                {
                    message = "unknown color " + index;
                }
                return new String[] { message };
            }
        });
        return commands;
    }
    
    public static void main(String[] args)
    {
        Thread t = new Thread(Paint.getInstance(), "Paint");
        t.start();
    }
}
